local _ENV,_START = hf_setenv('new_bind_activity',true)

local skynet     = require "skynet.manager"
local constant   = require "constant"
local util       = require "util"
local utils      = require "utils"
local reason     = require "reason"
local game_def   = require "game_def"
local sharedata  = require "skynet.sharedata"
local cjson      = require "cjson"
local mail_def   = require "mail_def"
local server_config = dofile(skynet.getenv("server_config"))

local math_random = math.random
local math_floor = math.floor
local table_insert = table.insert

local CMD = {}
function init()
    global_configs = nil
    redis_pool = nil
    conn = nil

    self_act_id = nil
    self_service_name = nil
    self_rank_service_addr = nil
    self_open_state = nil

    rank_begin_time = 0 --本周排行榜开始时间
    last_rank_end_time = 0 --上周排行开始时间
    gm_time = 0
    is_temp_close = false

    hf_set_sentinel_end(_ENV)
end

local function make_card_id(sign,number)
    return sign * 100 + number
end

local function get_act_key()
    return self_service_name .. "_" .. self_act_id
end

local function make_player_act_key(uid)
    return "data_" .. uid
end

local function get_activity_time()
    return gm_time + util.get_now_time()
end

local function init_activity_data()
    local key = get_act_key()
    local activity = global_configs.activity[self_act_id]
    local expire_time = utils.get_time_by_string(activity.ac_end_time)--过期时间
    local now = get_activity_time()
    rank_begin_time = now

    local ok = skynet.call(".msg_handler","lua","init_activity_data",self_act_id,key,expire_time,now)
    if not ok then
        errlog("init_activity_data====error===")
    end
end

local function on_activity_start()
    init_activity_data() --初始化活动数据
end

local function on_activity_end(is_temp_close)
    self_open_state = false
    is_temp_close = is_temp_close
    skynet.retpack(true)
end

local function is_cross_week(curr_time)
    if util.is_same_week(rank_begin_time,curr_time) then
        return false
    end

    return true
end

local function check_close_activity(cross_week)
    --临时关闭
    if is_temp_close then
        skynet.send(self_rank_service_addr,"lua", "exit")
        skynet.exit()
        return
    end

    --到点关闭
    if cross_week and not self_open_state then
        skynet.send(self_rank_service_addr,"lua", "close_rank")
        skynet.exit()
    end
end

local function send_rank_award(awar_list)
    local mail_list = {}
    for rank,v in pairs(awar_list) do
        local mail = {}
        mail.uid = v.uid
        mail.title = mail_def.NEW_BIND_TITLE
        local coins = math_floor(v.award_coins/100)
        mail.content = string.format(mail_def.NEW_BIND_CONTENT,rank,coins)
        mail.coins = v.award_coins
        mail.mail_type = 2
        mail.op_user = mail_def.OP_USER

        table_insert(mail_list,mail)
    end
    
    print("send_rank_award=========",tostring_r(mail_list))
    local url = constant.ADD_MAIL_URL
    R().hallsvr(1):call('.msg_handler','common_post_data',url,{award_list = mail_list})
end

function do_check_week_event()
    --检查跨周发奖励,检查跨周清数据
    local curr_time = get_activity_time()
    local key = get_act_key()
    local cross_week =  is_cross_week(curr_time)
    if cross_week then
        local award_list = {}
        local activity = global_configs.activity[self_act_id]
        local rank_list = skynet.call(self_rank_service_addr,"lua","get_curr_rank")
        for rank,rank_data in pairs(rank_list) do
            local award_coins = 0
            for _,rank_award in pairs(activity.ac_content.rank_award) do
                if rank >= rank_award.rank_min and rank <= rank_award.rank_max then
                    award_coins = rank_award.coins
                    break
                end
            end
            table_insert(award_list,{uid = rank_data.uid,award_coins = award_coins,nickname = rank_data.name})
        end
        send_rank_award(award_list) --发邮件奖励
        skynet.send(self_rank_service_addr,"lua", "update_rank_exvalue",award_list) --设置排行榜上的奖励值
        skynet.send(self_rank_service_addr,"lua", "reset_rank")
        skynet.send(".msg_handler","lua","set_award_status",self_act_id,key)

        last_rank_end_time = rank_begin_time
        rank_begin_time = curr_time
        skynet.send(".msg_handler","lua","clear_week_data",self_act_id,key,last_rank_end_time,rank_begin_time)
        dbglog("week_clear_data===sucess===")

        billlog({op="new_bind_week_award",act_id = act_id,award_list = award_list})
    end

    check_close_activity(cross_week)
end

local function check_week_event()
    while true do
        local ok, ret = xpcall(do_check_week_event,debug.traceback)
        if not ok then
            errlog(ret)
        end

        skynet.sleep(1000)
    end
end

function CMD.start(preload)
    self_act_id = preload.act_id
    self_service_name = preload.service_name
    self_open_state = true

    --启动排行榜服务
    local activity = global_configs.activity[self_act_id]
    local service_conf = game_def.ACIVITY_SERVICE_MAP[activity.ac_type]
    if service_conf and service_conf.rank_service_name then
        local service_addr = skynet.newservice(service_conf.rank_service_name)
        skynet.name("." .. service_conf.rank_service_name,service_addr)
        local preload = {
            redis_host  = assert(server_config.redis_conf.host),
            redis_port  = assert(tonumber(server_config.redis_conf.port)),
            redis_db    = assert(tonumber(server_config.redis_conf.db)),
            redis_auth  = server_config.redis_conf.auth,
            activity_id = self_act_id,
        }
        skynet.call(service_addr,"lua", "start", preload)
        self_rank_service_addr = service_addr
    end

    on_activity_start()
    skynet.fork(check_week_event)

    skynet.retpack(true)
end

function CMD.on_activity_end(is_force)
    on_activity_end(is_force)
end

local function get_player_rank(uid)
    if not self_rank_service_addr then
        return 0
    end

    local rank = skynet.call(self_rank_service_addr,"lua", "get_player_rank",uid)
    if not rank then
        return 0
    end

    return rank
end

local function update_player_rank(uid,score)
    if not self_rank_service_addr then
        return 
    end

    skynet.send(self_rank_service_addr,"lua", "update_rank",uid,score)
end

local function get_rank_list(rank_type)
    if not self_rank_service_addr then
        return {}
    end

    local rank_list
    if rank_type == game_def.ACT_RANK_TYPE_NEW_BIND_CUR then
        rank_list = skynet.call(self_rank_service_addr,"lua","get_curr_rank")
    elseif rank_type == game_def.ACT_RANK_TYPE_NEW_BIND_LAST then
        rank_list = skynet.call(self_rank_service_addr,"lua","get_last_week_rank")
    else
        errlog("unkown rank_type")
    end
    print("get_rank_list===========2222",rank_list,tostring_r(rank_list))

    return rank_list and rank_list or {}
end

local function make_player_act_data(uid,player_data,conf)
    local content = conf.ac_content
    local data = {
        bind_uid = player_data.bind_uid,
        double_timestr = content.double_start_time .. "-" .. content.double_end_time,
        free_count = (player_data.free_count or 0) + (player_data.bind_count or 0),
        cost = content.award_cost,
        my_score = player_data.score or 0,
        my_rank  = get_player_rank(uid),
        award_count = player_data.award_count or 0,
        invite_number = player_data.invite_number or 0,
        history_free_count = player_data.history_free_count or 0,
    }

    return data
end

function CMD.get_player_activity_data(uid)
    local activity = global_configs.activity[self_act_id]
    if not activity then
        return skynet.retpack(false)
    end

    local key = get_act_key()
    local player_data = skynet.call(".msg_handler","lua", "get_player_activity_data",self_act_id,key,uid)
    if not player_data then
        return skynet.retpack(false)
    end

    local player_act_data = make_player_act_data(uid,player_data,activity)
    if not player_act_data then
        return skynet.retpack(false)
    end
    local ret_data = {new_bind_activity = player_act_data}
    return skynet.retpack(ret_data)
end

function CMD.bind_player(data)
    local activity = global_configs.activity[self_act_id]
    if not activity or not activity.ac_content then
        return skynet.retpack(false)
    end

    local key = get_act_key()
    local bind_add_count = activity.ac_content.bind_add_count or 0
    local player_data = skynet.call(".msg_handler","lua", "bind_player",self_act_id,key,data,bind_add_count)
    if not player_data then
        return skynet.retpack(false)
    end

    local ret_data = make_player_act_data(data.src_uid,player_data,activity)
    billlog({op="new_bind_player",uid = data.src_uid,bind_uid = data.bind_uid})

    return skynet.retpack(ret_data)
end

local function add_player_coins(uid,coins)
    if coins <= 0 then
        return
    end

    local ok,succ,ret = R().basesvr({key=uid}):call('.msg_handler','add_coins',
    uid,coins,reason.NEW_BIND_LUCKY_DRWA)
    if not ok or not succ or not ret then
        errlog("add_player_coins_error")
        return
    end
end

function CMD.new_bind_lucky_draw(data)
    local activity = global_configs.activity[self_act_id]
    if not activity or not activity.ac_content then
        return skynet.retpack(false)
    end

    local key = get_act_key()
    local uid = data.uid
    local ret_data = skynet.call(".msg_handler","lua","new_bind_lucky_draw",self_act_id,key,uid,activity)
    if not ret_data then
        return skynet.retpack(false)
    end

    --更新排行榜还有加钱
    update_player_rank(uid,ret_data.player_data.score)
    add_player_coins(uid,ret_data.card_data.award_coins)

    local player_act_data = make_player_act_data(uid,ret_data.player_data,activity)
    local is_award = ret_data.card_data.award_coins > 0 or ret_data.card_data.award_score > 0
    local award_coins = ret_data.card_data.award_coins
    local data = {
        card = ret_data.card_data.card_num,
        is_award = is_award,
        coins = award_coins,
        score = ret_data.card_data.award_score,
        new_bind_activity = player_act_data,
    }

    billlog({op="new_bind_award",uid = uid,pay_coins = ret_data.pay_coins or 0,award_coins = award_coins})

    return skynet.retpack(data)
end

function CMD.get_rank_list(data)
    local rank_list = get_rank_list(data.rank_type)
    local ret_rank_list = {}
    for _,rank_data in pairs(rank_list) do
        local data = {
            uid  = rank_data.uid,
            name = rank_data.name,
            icon = rank_data.icon,
            value = rank_data.value,
            is_robot = rank_data.is_robot,
            extra_value = rank_data.exvalue or 0,
            vip_level = rank_data.vip_level,
            icon_border = rank_data.icon_border
        }
        table_insert(ret_rank_list,data)
    end

    local key = get_act_key()
    local btime,etime = skynet.call(".msg_handler","lua","get_week_rank_time",self_act_id,key,data.rank_type)

    local ret_data = {
        rank_begin_time = btime or 0,
        rank_end_time   = etime or 0,
        rank_list = ret_rank_list,
    }

    skynet.retpack(ret_data)
end

function CMD.add_rank_robot(data)
    if not self_rank_service_addr then
        return skynet.retpack(false)
    end

    local icon_library = global_configs.icon_library
    local icon = icon_library[math_random(1,#icon_library)]
    local ok = skynet.call(self_rank_service_addr,"lua", "add_robot",data.name,icon,data.score)
    if not ok then
        return skynet.retpack(false)
    end

    return skynet.retpack(true)
end

function CMD.add_rank_robot_score(data)
    if not self_rank_service_addr then
        return skynet.retpack(false)
    end

    local ok = skynet.call(self_rank_service_addr,"lua", "add_robot_value",data.uid,data.score)
    if not ok then
        return skynet.retpack(false)
    end

    return skynet.retpack(true)
end

function CMD.get_act_store()
    local key = get_act_key()
    local store_coins = skynet.call(".msg_handler","lua","get_act_store",self_act_id,key)
    if not store_coins then
        return skyent.retpack(false)
    end

    skynet.retpack(store_coins)
end

function CMD.set_act_store(data)
    local key = get_act_key()
    local ok = skynet.call(".msg_handler","lua","set_act_store",self_act_id,key,data.coins)
    if not ok then
        return skyent.retpack(false)
    end

    skynet.retpack(true)
end

function CMD.set_gm_time(data)
    gm_time = data
    skynet.retpack(true)
end

function dispatch_cmd(session,source,action,...)
    if not CMD[action] then
        errlog("unkown action", action)
    end

    CMD[action](...)
end

function start()
    skynet.start(function()
        skynet.dispatch("lua", function(session,source,action,...)
            dispatch_cmd(session,source,action,...)
        end)

        -- sharedata.query("global_configs")
        -- global_configs = setmetatable({},{
        --     __index = function(t,k)
        --         return sharedata.query("global_configs")[k]
        --     end
        -- })
        global_configs = setmetatable({},{
            __index = function(t,k) 
                --return sharedata.query("global_configs")[k]
                return sharedata.query(k)
            end
        })
    end)
end

_START(function()
    print('now this service is starting')
    init()
    start()
end)